/**
 * esprima 经过两个步骤转换成抽象语法树
 * 1. 把源代码进行分割，得到一个 token 的数组
 * 2. 把这个 token 的数组转换成一个抽象语法树
 */
// // 把JS源代码转成AST语法树
// const esprima = require('esprima');

// const sourceCode = `10+20`;

// // 生成 AST
// const ast = esprima.parseModule(sourceCode, { jsx: true, tokens: true });

// console.log(ast);

/**
 * 状态机实现词法分析，
 * 分词
 */

const NUMBERS = /[0-9]/;

const Number = 'Numeric';
const Plus = 'Punctuator';

let currentToken;
const tokens = [];

function emit(token) {
    currentToken = { type: "", value: "" };
    tokens.push(token);
}

function number(char) {
    if (NUMBERS.test(char)) { // 数字
        currentToken.value += char;
        return number;
    } else if (char == "+" || char == "-") { // 加号
        emit(currentToken);
        emit({ type: Plus, value: '+' });
        currentToken = {
            type: Number,
            value: ''
        }
        return number;
    }
}

/**
 * 接收一个字符，返回下一个状态的函数
 * @param {*} char 
 */
function start(char) {
    if (NUMBERS.test(char)) {
        currentToken = {
            type: Number,
            value: ''
        }
        // 进入新的状态
        return number(char);
    }
    throw new TypeError('函数名必须是字符 ' + char);
}

// 分词
function tokenizer(input) {
    let state = start;
    for (let char of input) {
        state = state(char);
    }
    if (currentToken.value.length) {

        emit(currentToken);
    }
}

tokenizer('10+20')
console.log(tokens);
/**
[
    { type: 'Numeric', value: '10' },
    { type: 'Punctuator', value: '+' },
    { type: 'Numeric', value: '20' }
]
*/